﻿-- $Revision: 42 $

----------------------------
--      Localization      --
----------------------------

local L = LibStub("AceLocale-3.0"):GetLocale("BunchOfBars")

----------------------------------
--      Local Declaration      --
----------------------------------


BunchOfBars.moduleorder = {}
BunchOfBars.order = {}
BunchOfBars.Lside = {}
BunchOfBars.Rside = {}
local regions = {}
----------------------------------
--      Module Declaration      --
----------------------------------

local DogTag = LibStub("LibDogTag-3.0")
LibStub("LibDogTag-Unit-3.0")


----------------------------------
--      Module Functions        --
----------------------------------

function BunchOfBars:OnProfileEnable() -- will be called when our profile is reset
	self:Print(L["You need to reload your user interface (/rl) for this reset to take effect."])
	self:UpdateAll()
end


function BunchOfBars:CreateMaster(name, parent, style, suffix)
	if self.master[name] then
		self:DestroyMaster(name)
	end

	local frame = CreateFrame("Frame", "BunchOfBarsFrame_"..name.."_", parent, "SecureGroupHeaderTemplate")
	frame.head = name
	frame.suffix = suffix
	frame.style = style

	frame:SetMovable(true)
	frame:SetClampedToScreen(true)
	
	frame:SetHeight(1)
	frame:SetWidth(1)
	self:ConfigMaster(frame)

	return frame
end

function BunchOfBars:DestroyMaster(name)
	self.master[name]:Hide()
	self.master[name] = nil
end
function BunchOfBars:ConfigMaster(frame)
	frame:SetAttribute("showRaid", true)
	frame:SetAttribute("showParty", self.db.profile.visual.party)
	frame:SetAttribute("showPlayer", true)
	frame:SetAttribute("showSolo", self.db.profile.visual.solo)
	frame:SetAttribute("yOffset", - frame.style.yoffest)

	frame:SetAttribute("groupBy", (self.db.profile.visual.groupby == "NONE") and nil or self.db.profile.visual.groupby)
	frame:SetAttribute("sortMethod", self.db.profile.visual.sortby)
	frame:SetAttribute("groupingOrder", self.db.profile.visual.orderstr)
	frame:SetAttribute("groupFilter", self.db.profile.visual.filterstr)

	frame:SetAttribute("columnSpacing", frame.style.columnspacing)
	frame:SetAttribute("columnAnchorPoint", "LEFT")
	frame:SetAttribute("maxColumns", ceil(40 / self.db.profile.visual.players))
	frame:SetAttribute("unitsPerColumn", self.db.profile.visual.players)

	frame.initialConfigFunction = self.ConfigureFrame

	frame:SetAttribute("template", "SecureUnitButtonTemplate")
end

function BunchOfBars:PositionAndScale()
	self.master.core:SetScale(self.db.profile.visual.scale)
	local s = self.master.core:GetEffectiveScale()
	local x, y = self.db.profile.visual.x / s, self.db.profile.visual.y / s

	self.master.core:ClearAllPoints()
	self.master.core:SetPoint("TOPLEFT", UIParent, "BOTTOMLEFT", x, y)
end

function BunchOfBars.OnAttributeChanged(frame, name, value)
	if name ~= "unit" then return end -- we are only interrested in the unit attribute

	if frame.unit and not value then
		BunchOfBars:ModuleOnInactive(frame)		
		frame.unit = nil
	elseif value then
		frame.unit = value
	end
end

function BunchOfBars.OnDragStart()
	if not BunchOfBars.db.profile.visual.locked and not InCombatLockdown() then
		BunchOfBars.master.core:StartMoving()
	end
end

function BunchOfBars.OnDragStop()
	BunchOfBars.master.core:StopMovingOrSizing()

	local x,y = BunchOfBars.master.core:GetLeft(), BunchOfBars.master.core:GetTop()
	local s   = BunchOfBars.master.core:GetEffectiveScale()

	BunchOfBars.db.profile.visual.x = x*s
	BunchOfBars.db.profile.visual.y = y*s
end

function BunchOfBars.frame_menu(frame)
	if frame.head ~= "core" then return end
	local type, num
	local unit = frame.unit

	if UnitIsUnit(unit, "player") then
		type = PlayerFrameDropDown
	elseif UnitIsUnit(unit, "target") then
		type = TargetFrameDropDown
	else
		num = unit:match("^party(%d)$")
		if num then
			type = _G["PartyMemberFrame" .. num .. "DropDown"]
		else
			num = unit:match("^raid(%d%d?)$")
			if num then
				type = FriendsDropDown
				type.displayMode = "MENU"
				type.initialize = RaidFrameDropDown_Initialize
			end
		end
	end

	if type then
		HideDropDownMenu(1)
		type.unit = unit
		type.name = UnitName(unit)
		type.id = this:GetID()
		ToggleDropDownMenu(1, nil, type, "cursor")
	end
end

function BunchOfBars.OnShow()
	if not this.visible then
		this.visible = true
		local parent = this:GetParent()
		BunchOfBars.frames[parent.head][this.unit] = this

		BunchOfBars:ModuleOnUpdate(this)
		BunchOfBars.master.core:StopMovingOrSizing() -- seems to fix a bug where you can't stop dragging
	end
end

function BunchOfBars.OnHide()
	if this.visible then
		this.visible = nil
		local parent = this:GetParent()
		if not UnitExists(this.unit) and BunchOfBars.frames[parent.head][this.unit] then
			BunchOfBars.frames[parent.head][this.unit] = nil
		end
	end
end


function BunchOfBars.ConfigureFrame(frame)
local parent = frame:GetParent()
	frame:SetAttribute("initial-width", parent.style.width)
	frame:SetAttribute("initial-height", parent.style.height)
	frame:SetAttribute("unitsuffix", parent.suffix)
	frame:SetAttribute("type1", "target")
--	frame:SetAttribute("*type1", "target")
	frame.menu = BunchOfBars.frame_menu
	frame:SetAttribute("initial-unitwatch", (parent.suffix and true))
	frame:RegisterForClicks("AnyUp")
	frame:RegisterForDrag("LeftButton")

	frame:SetScript("OnDragStart"		, BunchOfBars.OnDragStart)
	frame:SetScript("OnDragStop"		, BunchOfBars.OnDragStop)
	frame:SetScript("OnShow"		, BunchOfBars.OnShow)
	frame:SetScript("OnHide"		, BunchOfBars.OnHide)
	frame:SetScript("OnAttributeChanged"	, BunchOfBars.OnAttributeChanged)

	frame:SetAlpha(1.0)

	frame:SetBackdrop({ bgFile = "Interface\\Tooltips\\UI-Tooltip-Background" })
	frame:SetBackdropColor(0, 0, 0, BunchOfBars.db.profile.visual.bgtransparent)

	BunchOfBars:ModuleOnCreate(frame)
	BunchOfBars:UpdateLayout(frame) -- apperantly we are able to change the size of the frame here, even in combat
	BunchOfBars:UpdateSide(frame)

	ClickCastFrames[frame] = true
end


function BunchOfBars:ForceUpdate()
	if not InCombatLockdown() and self.master then
		-- this will trigger the blizzard code to update all units and reshow the frames
--		self.master:SetAttribute("unitsPerColumn", self.db.profile.visual.players)
	end
end


function BunchOfBars:ModuleOnCreate(frame)
	frame.parts = {}
	local modules = {}
	for name,module in self:IterateModules() do
		modules[name] = module
	end
	for i,name in ipairs(self.moduleorder) do
		local parent = frame:GetParent()
		if modules[name].head[parent.head] then
			frame.parts[name] = modules[name]:OnCreate(frame)
		end
	end
end

function BunchOfBars:ModuleOnUpdate(frame)
	if not UnitExists(frame.unit) then return end
	for name,module in self:IterateModules() do
		if frame.parts[name] then
			module:OnUpdate(frame)
		end
	end
end

function BunchOfBars:ModuleOnInactive(frame)
	for name,module in self:IterateModules() do
		if self:IsEnabled(module) then
			module:OnInactive(frame)
		end
	end
end
function BunchOfBars:ModulesOrder()
	self.moduleorder = {}

	for name,module in self:IterateModules() do
		if self:IsEnabled(module) then
			if module.db.profile.order then
				local done = false
				for k,v in ipairs(self.moduleorder) do
					if not self:GetModule(v).db.profile.order or module.db.profile.order < self:GetModule(v).db.profile.order then
						table.insert(self.moduleorder, k, name)
						done = true
						break
					end
				end
				if not done then
					table.insert(self.moduleorder, name)
				end
			else
				table.insert(self.moduleorder, name)
			end
		end
	end
end
function BunchOfBars:UpdateLayoutOrder()
	self.order = {}

	for name,module in self:IterateModules() do
		if self:IsEnabled(module) then
			if module.db.profile.position then
				local done = false
				for k,v in ipairs(self.order) do
					if module.db.profile.position < self:GetModule(v).db.profile.position then
						table.insert(self.order, k, name)
						done = true
						break
					end
				end
				if not done then
					table.insert(self.order, name)
				end
			end
		end
	end
end
function BunchOfBars:UpdateSideOrder()
	self.Lside = {}
	self.Rside = {}

	for name,module in self:IterateModules() do
		if self:IsEnabled(module) then
			if module.db.profile.side == "LEFT" then
				table.insert(self.Lside, name)
			elseif module.db.profile.side == "RIGHT" then
				table.insert(self.Rside, name)
			end
		end
	end
end
--[[ function BunchOfBars:UpdateLayout(frame)
	for k,v in ipairs(self.order) do
		if frame.parts[v] then
			frame.parts[v]:SetFrameLevel(k+10)
		end
	end


end ]]

function BunchOfBars:UpdateLayout(frame)
	for n, p in pairs(frame.parts) do

		local db, inout
		if self:GetModule(n).db.profile.style then
			db = self:GetModule(n).db.profile.style
			if (not db.inout) then
				inout = 2
			else
				inout = db.inout
			end
		else
			break
		end
		if inout == 2 and db.position then
			p:ClearAllPoints()
			p:SetPoint(db.position, frame, db.position, db.xof, db.yof)
			if db.width == 0 then
				p:SetPoint(positions_r[inout][db.position][1], frame, - db.xof, db.yof)
			elseif db.width then
				p:SetWidth(db.width)
			end
			if db.height == 0 then
				p:SetPoint(positions_r[inout][db.position][2], frame, db.xof, - db.yof)
			elseif db.height then
				p:SetHeight(db.height)
			end
		elseif inout == 1 and db.position then
			p:ClearAllPoints()
			p:SetPoint(positions_r[inout][db.position], frame, db.position, db.xof, db.yof)
			p:SetWidth(db.width)
			p:SetHeight(db.height)
		end
		if db.strata then
			p:SetFrameLevel(db.strata + 1)
		end
	end
end
function BunchOfBars:UpdateSide(frame)
	local last = frame
	local space = self:GetSetPadding("left")
	local scale = self.defaults.profile.visual.leftscale
	for _, name in pairs(self.Lside) do
		frame.parts[name]:ClearAllPoints()
		frame.parts[name]:SetScale(scale)
		frame.parts[name]:SetPoint("BOTTOMRIGHT", last, "BOTTOMLEFT", - space , 0)
		last = frame.parts[name]
		space = 1
	end
	last = frame
	space = self:GetSetPadding("right")
	scale = self.defaults.profile.visual.rightscale
	for _, name in pairs(self.Rside) do
		frame.parts[name]:ClearAllPoints()
		frame.parts[name]:SetScale(scale)
		frame.parts[name]:SetPoint("BOTTOMLEFT", last, "BOTTOMRIGHT", space , 0)
		last = frame.parts[name]
		space = 1
	end
end

function BunchOfBars:UpdateLayouts()
	for name,frames in pairs(self.frames) do
		for _, frame in pairs(frames) do
--			self:UpdateSide(frame)
			self:UpdateLayout(frame)
		end
	end
end

function BunchOfBars:UpdateAll()
	for name,frames in pairs(self.frames) do
		for _, frame in pairs(frames) do
--			self:UpdateLayout(frame)
			self:ModuleOnUpdate(frame)
		end
	end
end

function BunchOfBars:SetModuleConfig()
	for name,module in self:IterateModules() do
		if module.master then
			module:Config()
		end
	end
end
function BunchOfBars:ResetPosition()
	self.master.core:ClearAllPoints()
	self.master.core:SetPoint("CENTER", UIParent, "CENTER", 0, 0)
end

function BunchOfBars:HideShowParty()
	if self.db.profile.visual.hideparty and not partyhidden then
		partyhidden = true

		for i = 1, 4 do
			local frame = _G["PartyMemberFrame"..i]
			frame:UnregisterAllEvents()
			frame:Hide()
			frame.Show = function() end
		end
		
		UIParent:UnregisterEvent("RAID_ROSTER_UPDATE")
	elseif partyhidden then
		partyhidden = false

		for i = 1, 4 do
			local frame = _G["PartyMemberFrame"..i]
			frame.Show = nil
			frame:RegisterEvent("PARTY_MEMBERS_CHANGED")
			frame:RegisterEvent("PARTY_LEADER_CHANGED")
			frame:RegisterEvent("PARTY_MEMBER_ENABLE")
			frame:RegisterEvent("PARTY_MEMBER_DISABLE")
			frame:RegisterEvent("PARTY_LOOT_METHOD_CHANGED")
			frame:RegisterEvent("UNIT_PVP_UPDATE")
			frame:RegisterEvent("UNIT_AURA")
			frame:RegisterEvent("UNIT_PET")
			frame:RegisterEvent("VARIABLES_LOADED")
			frame:RegisterEvent("UNIT_NAME_UPDATE")
			frame:RegisterEvent("UNIT_PORTRAIT_UPDATE")
			frame:RegisterEvent("UNIT_DISPLAYPOWER")

			UnitFrame_OnEvent("PARTY_MEMBERS_CHANGED")
			
			_G.self = frame
			PartyMemberFrame_UpdateMember()
		end
		
		UIParent:RegisterEvent("RAID_ROSTER_UPDATE")
	end
end